#include "BondCalendar.h"
#include "BondContainer.h"
#include <core/time/date.h>
#include <uam/ServerTimeMgr.h>
#include <QDate>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
//#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// class CBondCalendar

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBondCalendar::CBondCalendar()
{
}

CBondCalendar::~CBondCalendar()
{
	Clear( );
}

CBondCalendar& CBondCalendar::instance()
{
	static CBondCalendar s_bc;
	return s_bc;
}

void CBondCalendar::Clear( )
{
	m_holiday.date.clear();
	return;
}

void CBondCalendar::Add( int nDate, BondHoliday &element )
{
	if(nDate <= 0)
		return;
	std::map<int, BondHolidayList>::iterator it = m_holiday.date.find(nDate);
	if(it == m_holiday.date.end())
	{
		BondHolidayList list;
		list.holidays.push_back(element);
        m_holiday.date.emplace(std::make_pair(nDate, list));
	}
	else
	{
		// [内存优化][scofined.qi]
		// 确保vector中没有浪费的空间,每多一个就浪费53字节
		std::vector<BondHoliday>& holidays = it->second.holidays;
		if (holidays.size() >= holidays.capacity())
			holidays.reserve(holidays.capacity() + 1);
		holidays.push_back(element);
	}
	//m_holiday.m_data.push_back( element);
	//int nIndex = m_holiday.m_data.size()-1;
	return;// nIndex;
}

int CBondCalendar::GetSize() 
{ 
	return m_holiday.date.size(); 
}

bool CBondCalendar::GetHolidayByDate(const std::string &szCountry, const std::string &szMarket, int nDate)
{
	int year = nDate/10000;
	int month = (nDate/100)%100;
	int day = nDate%100;

	QDate date(year, month, day);

	std::map<int, BondHolidayList>::iterator it;
	it = m_holiday.date.find(nDate);
	if(it != m_holiday.date.end())
	{
		std::vector<BondHoliday>::iterator it2;
		for(it2 = it->second.holidays.begin(); it2 != it->second.holidays.end(); it2 ++)
		{
			BondHoliday& bh=*it2;
			if( strcmp(bh.country,szCountry.c_str())==0 && 
				strcmp(bh.market,szMarket.c_str())==0)
			{
				if( strcmp(bh.status,"H")==0 )
					return true;
				else if (date.dayOfWeek() >= 6)
					return false;
			}
		}
	}
	
	if (date.dayOfWeek() >= 6)
		return true;

	return false;
}

void CBondCalendar::CalcHolidays(const std::string sMarket, time_t tBegin, time_t tEnd, BondHolidays_ &bhd_)
{
	int nBegin = TimeToInt(tBegin);
	int nEnd = TimeToInt(tEnd);

	bhd_.nNaturalDays = DiffDays(nBegin, nEnd);

	std::string sCountry("CNY");

	int nHolidays = 0;
	for (int nDay = 0; nDay < bhd_.nNaturalDays;++nDay)
	{
		if (IsHoliday(sCountry, sMarket, nBegin))
			nHolidays++;

		nBegin =  IncreaseOneDay(nBegin);
	}

	bhd_.nWorkingDays = bhd_.nNaturalDays - nHolidays;
}

bool CBondCalendar::GetBondHolidayById(const std::string &szMarket, int nDate, BondHoliday &stHoliday)
{
	std::map<int, BondHolidayList>::iterator it;
	it = m_holiday.date.find(nDate);
	if(it != m_holiday.date.end()){
		std::vector<BondHoliday>::iterator it2;
		for(it2 = it->second.holidays.begin(); it2 != it->second.holidays.end(); it2 ++){
			if(std::string(it2->market) == std::string(szMarket)){
				stHoliday = *it2;
				return true;
			}
		}
	}
	return false;
}

CBondHoliday& CBondCalendar::GetBondHoliday()
{
	return m_holiday;
}

bool CBondCalendar::IsHoliday_CHY(const CBondInfo& bondInfo, bool &isCIB, int &nDayCIB, int &nDaySSE)
{
    return IsHoliday_CHY_Time(bondInfo, ServerTimeMgr::instance().serverTime(), isCIB, nDayCIB, nDaySSE);
}

bool CBondCalendar::IsHoliday_CHY_Time(const CBondInfo& bondInfo, const time_t tNow, bool& isCIB, int& nDayCIB, int& nDaySSE)
{

    struct tm* tt = localtime(&tNow);

    int nNow = (tt->tm_year + 1900) * 10000 + (tt->tm_mon + 1) * 100 + tt->tm_mday;

    int nMautrityDate = atoi(bondInfo.GetMaturityDate());

    if (nNow > nMautrityDate)
        return false;//已过期
    //if (nNow / 10000 < nMautrityDate / 10000 - 2)return false;//大于第二年12.31日

    nDayCIB = 0; nDaySSE = 0;

    bool breakCIB = false;
    bool breakSSE = false;
    bool bFirst = true;
    static std::string CNY = "CNY";
    static std::string CIB = "CIB";
    static std::string SSE = "SSE";
    while (1)
    {
        bool bIsValid = false;
        if (GetHolidayByDate(CNY, CIB, nMautrityDate))
        {
            if (!breakCIB && (bFirst || nDayCIB > 0))
                nDayCIB++;

            bIsValid = true;
        }
        else
        {
            breakCIB = true;
        }
        if (GetHolidayByDate(CNY, SSE, nMautrityDate))
        {
            if (!breakSSE && (bFirst || nDaySSE > 0))
                nDaySSE++;

            bIsValid = true;
        }
        else
        {
            breakSSE = true;
        }

        bFirst = false;

        if (!bIsValid)
            break;
        IncreaseOneDay(nMautrityDate);
    }

    if (nDayCIB <= 0 && nDaySSE <= 0)
        return false;

    isCIB = true;
    if (nDayCIB == 0)
        isCIB = false;

    return true;

}

int CBondCalendar::IncreaseOneDay( int &nDate )
{
	time_t tTime = IntToTime(nDate);
	tTime += 24*60*60;
	nDate = TimeToInt(tTime);
	return nDate;
}

int CBondCalendar::ReduceOneDay(int &nDate)
{
	time_t tTime = IntToTime(nDate);
	tTime -= 24 * 60 * 60;
	nDate = TimeToInt(tTime);
	return nDate;
}


bool CBondCalendar::IsHoliday_CHY_Primary(const CBondInfo& bondInfo,const time_t tNow, bool &isCIB, int &nDayCIB, int &nDaySSE)
{
	return IsHoliday_CHY_Time(bondInfo, tNow, isCIB, nDayCIB, nDaySSE);
}

time_t CBondCalendar::IntToTime( int nDate )
{
	struct tm tt;
	memset(&tt,0,sizeof(tm));
	tt.tm_year = nDate/10000 - 1900;
	tt.tm_mon = (nDate/100)%100 - 1;
	tt.tm_mday = nDate%100;
	tt.tm_hour = 8;
	time_t t = mktime(&tt);

	return t;
}

int CBondCalendar::TimeToInt( time_t tTime )
{
	return qb::base::IntDate::timeToInt(tTime);
}

bool CBondCalendar::IsHoliday( const std::string &szCountry, const std::string &szMarket, int nDate )
{
	return GetHolidayByDate(szCountry,szMarket,nDate);
}

bool CBondCalendar::IsHoliday( const std::string &szCountry, const std::string &szMarket, time_t tTime )
{
	return IsHoliday(szCountry,szMarket,TimeToInt(tTime));
}

int CBondCalendar::DiffDays( int nStartDate,int nEndDate )
{
	time_t tStartTime = IntToTime(nStartDate);
	time_t tEndTime = IntToTime(nEndDate);

	time_t nDiffTime = tEndTime-tStartTime;

	return nDiffTime/24/3600;
}

int CBondCalendar::IncreaseDay( int &nDate,int nDays )
{
	time_t tTime = IntToTime(nDate);
	tTime += 24*60*60*nDays;
	nDate = TimeToInt(tTime);
	return nDate;
}

void CBondCalendar::DumpStatus(int mode)const
{
}
